﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using WebAppMatrix.Extensions;

namespace WebAppMatrix.Caching
{
    public class DictionaryCacheProvider : CacheBase
    {
        private static Dictionary<string, object> _cache = new Dictionary<string, object>();
        ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

        #region CacheBase方法

        public override T Get<T>(string key, params object[] keyArgs)
        {
            key = CacheBase.BuildKey(key, keyArgs);

            _lock.EnterReadLock();
            object val;
            try
            {
                if (_cache.TryGetValue(key, out val))
                {
                    return Extensions.ReflectionExtensions.ConvertTo<object, T>(val);
                }
            }
            finally
            {
                _lock.ExitReadLock();
            }

            return default(T);
        }

        public override T Fetch<T>(string key, Func<T> callIfGetReturnsNull, params object[] keyArgs)
        {
            T val = Get<T>(key, keyArgs);
            if (val == null)
                val = callIfGetReturnsNull();

            return val;
        }

        public override T Fetch<T>(string key, Func<T> callIfGetReturnsNull, DateTime absoluteExpiration, params object[] keyArgs)
        {
            return Fetch<T>(key, callIfGetReturnsNull, keyArgs);
        }

        public override T Fetch<T>(string key, Func<T> callIfGetReturnsNull, TimeSpan slidingExpiration, params object[] keyArgs)
        {
            return Fetch<T>(key, callIfGetReturnsNull, keyArgs);
        }

        public override T Fetch<T>(string key, Action<T> callIfGetReturnsValue, Func<T> callIfGetReturnsNull, params object[] keyArgs)
        {
            T val = Fetch<T>(key, callIfGetReturnsNull, keyArgs);
            if (val != null)
                callIfGetReturnsValue(val);

            return val;
        }

        public override T Fetch<T>(string key, Action<T> callIfGetReturnsValue, Func<T> callIfGetReturnsNull, DateTime absoluteExpiration, params object[] keyArgs)
        {
            return Fetch<T>(key, callIfGetReturnsValue, callIfGetReturnsNull, keyArgs);
        }

        public override T Fetch<T>(string key, Action<T> callIfGetReturnsValue, Func<T> callIfGetReturnsNull, TimeSpan slidingExpiration, params object[] keyArgs)
        {
            return Fetch<T>(key, callIfGetReturnsValue, callIfGetReturnsNull, keyArgs);
        }

        public override void Insert(string key, object data, params object[] keyArgs)
        {
            key = CacheBase.BuildKey(key, keyArgs);

            _lock.EnterWriteLock();
            try
            {
                //增加新的值，如果key已存在则覆盖对应值，如果key不存在则新增。
                //和Add方法相比，如果key存在则会引发异常
                _cache[key] = data;
            }
            finally
            {
                _lock.ExitWriteLock();
            }
        }

        public override void Insert(string key, object data, DateTime absoluteExpiration, params object[] keyArgs)
        {
            Insert(key, data, keyArgs);
        }

        public override void Insert(string key, object data, TimeSpan slidingExpiration, params object[] keyArgs)
        {
            Insert(key, data, keyArgs);
        }

        public override void Remove(string key, params object[] keyArgs)
        {
            key = CacheBase.BuildKey(key, keyArgs);

            _lock.EnterWriteLock();
            try
            {
                _cache.Remove(key);
            }
            finally
            {
                _lock.ExitWriteLock();
            }
        }

        public override void RemoveAll()
        {
            _lock.EnterWriteLock();
            try
            {
                _cache.Clear();
            }
            finally
            {
                _lock.ExitWriteLock();
            }
        }

        public override int Count()
        {
            return _cache.Count;
        }

        #endregion
    }
}
